<!DOCTYPE html>
<!-- saved from url=(0106)https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization?display=Print -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Custom Controls in Win32 API: Control Customization - CodeProject</title> 
	<link type="text/css" rel="stylesheet" href="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/Main.min.css">

	
<meta http-equiv="content-language" content="en-US">

<meta name="Description" content="Overview of techniques for customizing existing controls.; Author: Martin Mitáš; Updated: 11 Dec 2014; Section: Windows API; Chapter: Platforms, Frameworks &amp; Libraries; Updated: 11 Dec 2014">
<meta name="Keywords" content="C, Windows, Win32, Win64, Visual-Studio, Dev, VS2010,Windows API,Platforms, Frameworks &amp; Libraries,Free source code, tutorials">
<meta name="Author" content="Martin Mitáš">
<meta name="Rating" content="General">
<meta name="Revisit-After" content="1 days">
<meta name="application-name" content="CodeProject">
<meta name="google-translate-customization" content="d908bb7ce7aff658-4c2f3a504525c916-g629383f736781a8a-13">

<link rel="dns-prefetch" href="https://ajax.googleapis.com/"> 
<link rel="canonical" href="https://www.codeproject.com/Articles/646482/%2fArticles%2f646482%2fCustom-Controls-in-Win-API-Control-Customization">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - All Topics" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=1">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - Artificial Intelligence" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=31">
<link rel="alternate" type="application/rss+xml" title="CodeProject Lounge Postings" href="https://www.codeproject.com/webservices/LoungeRSS.aspx">
<meta name="robots" content="index, follow">
<link rel="search" type="application/opensearchdescription+xml" title="CodeProject" href="https://www.codeproject.com/info/OpenSearch.xml">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="apple-touch-icon" sizes="144x144" href="https://www.codeproject.com/favicon/apple-touch-icon.png"> 
<link rel="icon" type="image/png" sizes="32x32" href="https://www.codeproject.com/favicon/favicon-32x32.png"> 
<link rel="icon" type="image/png" sizes="16x16" href="https://www.codeproject.com/favicon/favicon-16x16.png"> 
<link rel="manifest" href="https://www.codeproject.com/favicon/manifest.json"> 
<link rel="mask-icon" href="https://www.codeproject.com/favicon/safari-pinned-tab.svg" color="#ff9900">
	
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "TechArticle",
  "headline": "Custom Controls in Win32 API: Control Customization",
  "url": "https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization",
  "discussionUrl": "https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization",
  "isFamilyFriendly": "true",
  "image": "https://www.codeproject.com/KB/vista/646482/Thumb-646482.png",
  "keywords": "C, Windows, Win32, Win64, Visual-Studio (VS2010)",
  "commentCount": "16",
  "editor" : {
    "@type" : "Person",
    "name" : "Martin Mitáš",
    "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
  },
  "license": "http://www.codeproject.com/info/cpol10.aspx",
  "publisher" : {
    "@type" : "Organization",
    "name" : "CodeProject"
  }
  "description": "Overview of techniques for customizing existing controls.",
  "upvoteCount": "51",
  "articleSection": "Windows API",
  "author" : [{
      "@type" : "Person",
      "name" : "Martin Mitáš",
      "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
    }],
  "datePublished": "2014-03-17",
  "dateCreated": "2014-03-17",
  "dateModified": "2014-12-11",
  "aggregateRating" : {
    "@type" : "aggregateRating",
    "ratingValue" : 4.95,
    "ratingCount" : 52,
    "bestRating" : 5,
    "worstRating" : 1
  },
}
</script>
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "item" : {
      "@id" : "/Chapters/8/Platforms-Frameworks-Libraries.aspx",
      "name" : "Platforms, Frameworks & Libraries"
    }
  },{
    "@type": "ListItem",
    "position": 2,
    "item" : {
      "@id" : "/KB/vista/",
      "name" : "Windows API"
    }
  }]
}
</script>
	<!--<base target="_top">--><base href="." target="_top">
	<script type="text/javascript" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/jquery.2.2.4.min.js.下载"></script><script type="text/javascript">//<![CDATA[
if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='%2fscript%2fJS%2fjquery-2.2.4.min.js' type='text/javascript' %3E%3C/script%3E"));
}//]]></script><script src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/jquery-2.2.4.min.js.下载" type="text/javascript"></script>
<script type="text/javascript">//<![CDATA[
function defrm () { /* thanks twitter */ document.write = ''; window.top.location = window.self.location;  setTimeout(function() { document.body.innerHTML = ''; }, 0);  window.self.onload = function(evt) { document.body.innerHTML = ''; }; }if (window.top !== window.self) {  try {  if (window.top.location.host) { /* will throw */ } else { defrm(); /* chrome */ }  } catch (ex) { defrm(); /* everyone else */ } }if (typeof(DemoUrl)!='undefined')   document.write(unescape('%3Cme')+'ta http'+'-equiv="re'+'fresh"                  con'+'tent="1;url='+DemoUrl+unescape('"%3CE'));

//]]>
</script>

	




<script type="text/javascript">
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-1735123-1']);
	_gaq.push(['_trackPageview']);
	_gaq.push(['_setDomainName', 'www.codeproject.com']);
	_gaq.push(['_setSessionTimeout', '1200']); 

	(function () {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
	})(); 
</script><script type="text/javascript" async="" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/ga.js.下载"></script>


</head>	

<body class="chrome chrome67 touch">

<a class="access-link" href="https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization?display=Print#Main"><img alt="Click here to Skip to main content" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/t.gif"></a>





<div class="page-background">

	
	

	

	
    <div id="ctl00_STM" class="site-top-menu fluid">
        <div class="main-content">
            
        </div>
    </div>

	
    <div id="ctl00_SH" class="site-header fluid">
        <div class="main-content">
            <div class="logo"><a href="https://www.codeproject.com/"><img id="ctl00_Logo" tabindex="1" title="CodeProject" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/logo250x135.gif" alt="Home" style="height:135px;width:250px;border-width:0px;"></a></div>
            <div class="promo"></div>
        </div>
    </div>

	<a href="https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization?display=Print#Main"><img alt="Click here to Skip to main content" class="access-link" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/t.gif"></a>

	
			
	

	<div id="A" class="container-content-wrap fluid print"> 
	<div class="container-content">


		<div class="clearfix">
			<div class="container-breadcrumb float-left ">
				<div><a href="https://www.codeproject.com/script/Content/SiteMap.aspx">Articles</a> » <a href="https://www.codeproject.com/Chapters/8/Platforms-Frameworks-Libraries.aspx">Platforms, Frameworks &amp; Libraries</a> » <a href="https://www.codeproject.com/KB/vista/">Windows API</a> » <a href="https://www.codeproject.com/KB/vista/#General">General</a></div>
			</div>

            <div class="float-left">
				
			</div>

			<div class="edit-links float-right">
				
			</div>

			<div class="article-nav float-right">
                
				
			</div>
		</div>

		<table class="extended container-article-parts" cellpadding="0" cellspacing="0">
        <tbody><tr valign="top">
		<td width="117px" class="article-wing-left">

			

		</td>
		<td>
			
			<div id="AT" class="container-article  fluid tight"> 

				<div class="article">

					<form name="aspnetForm" method="post" action="https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization?display=Print" id="aspnetForm" style="margin:0;padding:0">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="zwd8ugG8tEUGL/j34bBScD9QPZQxsRSYEq3w+euIhTga2NKbyGNGfdFKEb8RcT4rxJVIWeRTEAsqwFofQwMjQdX8j8uLCMJHy3GA4NeoShbUF5JgKLJaZJC0h3YYcyUKEDkwHnAcfzb+BuRcC45QXahLVkCpsUq9b0CAXeZzEQr0iBdiWZ8/RF218QzchHMVUPDi/GWofbvXn4GAmNqAs8Gt+CBEofHIrq5ZEEV2Xj2pjd19dcfrkiGHz2P7kXVESnLxvWz+VG/dgid2b0ZvWzejscaV9JaCbTK8Q+dYB2U5Nhx72N3Rbp89EPnoMQ+TNjNpQ8aQ22E9O8QD+EtKJywBD9S3I2EWcCHKZlwIXtGxPoIPXt9rZImSWx6Qq5W9wDLvY090AWfX4jPnD3FUV08BSrnSVmBiGS7+1TB8uH9XX8YgaSPu1TRGnQR71ZDGStMWcay1Jwsw0AvqUlKUhwJNyEdXX/d7uwioMucsHEhewbFEdzhpTWaVPIBOD4rCVzNvEkjlr5cz2COkNsVU2knjaHXfZ09BGOhHJT8+SJCXTdcXgmzThuUxJpzmoiFVmLYd8t+WaaAYlzG7j0G0Bvuv2TQSccUTDMrAW1X22F0QFcVteUC22/fPGK57gH3yR3Cl1Z3xUDfzWXNRcMybuD51TkJEoBbWh9rx7+NgmM36W40Clt97cdsCghAiJkngErzZpNDZC5ptUuIjaKuJDUnw2dLJBgczoPLSldIU7KUcMX+PI5hF+8lwqQAfSLOVvcvcHNjf0XdIyGgGpKgVGBOVqYvrb0D5C+k0LTdj3sxb++Zy1UXQS5H4tiv1ynIYXRyHuCtH0SqQi6I4gERP6+98x/fBP3HJQ0otNDyzVg2TjcYua6jKxGcWIuUFtqS0HWEb1ZoDB50EDXN2+HDdyI7Fwc9rf6oKlOniCnhurvmUc0BghcZ+KzZrHP+CQ2HLtogVykh+H7of7AbXLAfFxC83m3HOmY6RzTm9N4iodoWpzM0dm59dUm7DnwMmyuqauJWMtrq6A/7D6Jc4/bpI1k3/JJJH2T0fxhaC2uqELfIGrBR80+50oTcpdTYqhHMkApzF/oUmeelDXxSqLpafVrAAoxL7b3gMFIsW1O4AEGQ1sV4wHF1Xn7rABvwkFIODOUtDfqPg9WEnPEMgNStJmZ7sem0IAKvv2Hxa/DgHV1AepOJwYqHKp806yNXfe4Vcm+C4DJK5G8c2Od5m43zOvDfboUmrrRpJHfaKjWsSUJkmTZvMUSbeWNtm6lAX2dFvl9XTethmsdMlJ5mR1LZMi5+XOQL23RZUEYHzD6ZqEd5ZM0RQiYjxY3NQ6hTmupyGwHlR+k7drTq81wu4xj+SjZme0DyxSzWTUdJO+ZPWzHMOrFhJC8To+Otn1P291TcdkwP44CYTB+Eveu6etSxKMffnBlywPHL6CoCA+qmwPEGX+eSdxv789IwhOAsmAmHd0wzPUpQ2raM9xWv2wM8Vva5pCuBjOPvHquf4ZbruRq0hDmjfgNvoXRYsGxZome22bxXYH9hG2jM3gQJrTNfCSqlpXorjpo7laphmfD29lJWghbBE02m/FLAA1v3db80EdhjJfTbCFI561lznzzWMPF6kEpTuYyHAScmsBg9TLfqiBLjp4MV7l/MjgmNqAU0tbMAsI92A+ViuC43uc41n63AIXA23aUxDsdWbn8gLYvwDJd2K47p2vWT3A8/ye1XSgce1rgE8kj12SAIgW1Yr3R1qit/+7JrakqNMaaUzSgZTCMFFXHx5DmSvx2YJ3H3Ob6LU7UdU0rxsL1OyLUAj1A+DQQRFMcn1TxCXndSKhv4dohkU+hP0G3xPK5Ma+Vuz2JxxVztokTUcUg/Y+NHFudXXeXmACyFXLnBi10NpomPsMiJ9dd4hykqhVskmMIw+X7QC2O8oyxUESvA3Sc/7qg2Ya4+nl2lr3ApF5NpVqATgmxuUgeqGY2uybZDw+2hnXtKZppx7TLI3l4ZrFikc5BlHH++vitC6Bvl/ppNjWP/p15beuFdzLoFy6UomqF1Hto6AQOW380Hf5LmEKbPBiaHXU549wsRKiPEjOBlLtC/07wPHCuHGCiCFOTJSi5p9L1GwPQ+xlFFYOpzPnBb14W9/baxHlnD5hVzq/XyG6IrDLsxkbieZ7+fGFPAQs/BUMtgsG08YMJwJMUPfpD8qQ1TteWGhaYkRI08ZCh+U42QczmouqlwSTpetYahanHn6MTe+LFnm/2hYW/BaULzLfRE21R/YWC+jtYRT9v/eqls0f1kjlX5mOdtBy9dSmQ/qWwwEHndxBHbn47Sb0qPjn3UiFHTYgN85f2s9iPdcrLgsmfKlaeDIjoZ5X6kx/P3v/SjSq4Ekn4LSrk5sapNf7dLeDUq28AJ1o/BpAk8ogtx3o/df0v+7cubobwmXbGSkjZZ9FFBxn0KCvgI1C+aMe6gRpGDdRML/Luw8tSHlGPlYGHm1">
</div>

<div>

	<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="10C1FD69">
</div>

					
					 
					<div class="header">
					    <a name="Main"></a>

					    
					    <a name="_articleTop" id="_articleTop"></a>
					    <div class="title">
					        <h1 id="ctl00_ArticleTitle">Custom Controls in Win32 API: Control Customization</h1>
					    </div>

                        <div style="height:34px">
					        
					        <div class="entry float-left">

                                <img src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" id="ctl00_avatar" class="float-left avatar">

                                <div class="float-left">
                                    <div>
						                <span class="author"><a href="https://www.codeproject.com/script/Membership/View.aspx?mid=5807385" rel="author">Martin Mitáš</a></span>, 
						                <span class="date" title="Date last updated">
							            12 Dec 2014</span>
			                        </div>

                                    
						            
    						        	

                                </div>

    	                        	
                                <div class="float-left" style="margin: 25px 0 0 10px;">
	                                
	                            </div>
                         	    	
    
					        </div>

                            

						    <div id="ctl00_AdManagerWrap" class="float-right align-center">
                                
						    </div>

                        </div>

                        <div id="ctl00_description" class="summary">Overview of techniques for customizing existing controls.</div><span id="ctl00_thumbnailUrl" class="date" content="https://www.codeproject.com/KB/vista/646482/Thumb-646482.png"></span>			

                    </div>
                    
					
					

					

					
					
					

						
					

					

						
						<div id="contentdiv" class="text">
						



<ul class="download">
	<li><a href="https://www.codeproject.com/KB/vista/646482/customdraw.zip">Download Custom Draw Example - 64 KB</a></li></ul>

<h2>Articles in this series</h2>

<ul>
	<li><a href="http://www.codeproject.com/Articles/559385/Custom-Controls-in-Win32-API-The-Basics">Custom Controls in Win32 API: The Basics</a></li>	<li><a href="http://www.codeproject.com/Articles/617212/Custom-Controls-in-Win32-API-The-Painting">Custom Controls in Win32 API: The Painting</a></li>	<li><a href="http://www.codeproject.com/Articles/620045/Custom-Controls-in-Win32-API-Visual-Styles">Custom Controls in Win32 API: Visual Styles</a></li>	<li><a href="http://www.codeproject.com/Articles/624495/Custom-Controls-in-Win32-API-Standard-Messages">Custom Controls in Win32 API: Standard Messages</a></li>	<li>Custom Controls in Win32 API: Control Customization</li>	<li><a href="http://www.codeproject.com/Articles/744603/Custom-Controls-in-Win-API-Encapsulation-of-Cust">Custom Controls in Win32 API: Encapsulation of Customized Controls</a></li>	<li><a href="http://www.codeproject.com/Articles/1042516/Custom-Controls-in-Win-API-Scrolling">Custom Controls in Win32 API: Scrolling</a></li></ul>

<h2>Introduction</h2>

<p>This series is about implementation of custom controls. However, implementing new control from scratch is often a lot of work, and in many cases the desired effect can also be achieved by augmenting behavior, look or both of an existing control, often with much less effort. In today's article we will take a look on several techniques how to customize existing controls.</p>

<p>In addition, the topic is also interesting when you are implementing new control from scratch: Good controls allow the applicatoion some level of customization, and some customization techniques do require some support from the control itself. Hence, we will also discuss how to implement such support in a new control.</p>

<p>Note that there is no strict boundary between "customizing a control" and "using a control". The two cases overlap and different people may have different opinion where one ends and the other one begins. Actually, even setting of a control style (e.g. instructing the control to paint differently) can be understood as a simple example of control customization. For our purposes, we will use the term "control customization" for augmenting the control's look or behavior, which involves a (non-trivial) code on the application side.</p>

<p>The article shall present several customization techniques. They differ in many aspects, for example:</p>

<ul>
	<li>Whether they are specialized for a specific purpose (e.g. to only customize look of the control) or not,</li>	<li>whether they require special support from the control itself or not,</li>	<li>or whether they principally need cooperation of parent window (typically dialog) or not.</li></ul>

<h2>Owner Drawing</h2>

<p>First customization technique we take a look at is owner drawing. The technique is useful only for changing how the particular control (or its item) is painted, and it can only be used for controls which implement a support for it.</p>

<p>Controls which provide such support, always have some knob, which can be used by the application to specify that it shall paint the control (or its item) on its own. Depending on the control, the knob can be a window style bit or a flag in some structure (e.g. structure describing an item of the control).</p>

<p>When the knob is used, it causes the control to send <code>WM_DRAWITEM</code> to its parent instead of the normal painting code when handling <code>WM_PAINT</code> or <code>WM_PRINTCLIENT</code>. Also, depending on the control, <code>WM_MEASUREITEM</code> can precede the <code>WM_DRAWITEM</code>.</p>

<p>For some controls, the knob enables the owner-drawing for the control as a whole, for others it enables it for some or all items.</p>

<p>When the owner drawing is enabled, the control may send <code>WM_MEASUREITEM</code> to let the application determine, how large the item (or items) are so it can handle the items properly (e.g. setup scrollbars and layout of items etc.). As a rule of thumb, if the owner-drawing overrides painting of the whole control, this message is not sent at all. If all the items are supposed to have the same size, then it is sent once, usually during control creation in the context of <code>CreateWindow()</code>. If the item size can differ, it is sent for each item in the control (e.g. when the item is being inserted).</p>

<p>The table below summarizes the standard controls that can be owner-drawn. It specifies the knob for enabling the owner drawing, whether the control sends <code>WM_MEASUREITEM</code> (and if it does, whether it is sent once for all items or if it is sent for each item), and whether <code>WM_DRAWITEM</code> is called to paint whole control or if it is called for every item the owner drawing applies to.</p>


	<table class="grid"><thead>		<tr>			<th>Control</th>			<th>The Knob</th>			<th>Description</th>		</tr>	</thead>	<tbody>		<tr>			<td>Button (<code>"BUTTON"</code>)</td>			<td>Style <code>BS_OWNERDRAW</code></td>			<td>Sends <code>WM_DRAWITEM</code> to paint whole control.</td>		</tr>		<tr>			<td>Static (<code>"STATIC"</code>)</td>			<td>Style <code>SS_OWNERDRAW</code></td>			<td>Sends <code>WM_DRAWITEM</code> to paint whole control.</td>		</tr>		<tr>			<td rowspan="2">List box (<code>"ListBox"</code>)</td>			<td>Style <code>LBS_OWNERDRAWFIXED</code></td>			<td>Sends <code>WM_MEASUREITEM</code> once during control creation and <code>WM_DRAWITEM</code> on per-item basis.</td>		</tr>		<tr>			<td>Style <code>LBS_OWNERDRAWVARIABLE</code></td>			<td>Sends <code>WM_MEASUREITEM</code> as well as <code>WM_DRAWITEM</code> on per-item basis.</td>		</tr>		<tr>			<td rowspan="2">Combo box (<code>"ComboBoxEx32"</code>)</td>			<td>Style <code>CBS_OWNERDRAWFIXED</code></td>			<td>Sends <code>WM_MEASUREITEM</code> once during control creation and <code>WM_DRAWITEM</code> on per-item basis.</td>		</tr>		<tr>			<td>Style <code>CBS_OWNERDRAWVARIABLE</code></td>			<td>Sends <code>WM_MEASUREITEM</code> as well as <code>WM_DRAWITEM</code> on per-item basis.</td>		</tr>		<tr>			<td>List view (<code>"SysListView32"</code>) (with style <code>LVS_REPORT</code> only)</td>			<td>Style <code>LVS_OWNERDRAWFIXED</code></td>			<td>Sends <code>WM_MEASUREITEM</code> once during control creation and <code>WM_DRAWITEM</code> on per-item basis.</td>		</tr>		<tr>			<td>Tab control (<code>"SysTabControl32"</code>)</td>			<td>Style <code>TCS_OWNERDRAWFIXED</code></td>			<td>Sends <code>WM_DRAWITEM</code> on per-item basis. Note <code>WM_MEASUREITEM</code> is not sent, instead size specified by message <code>TCM_SETITEMSIZE</code> is used.</td>		</tr>		<tr>			<td>Header (<code>"SysHeader32"</code>)</td>			<td>Item flag <code>HDF_OWNERDRAW</code></td>			<td>Sends <code>WM_DRAWITEM</code> on per-item basis. Note <code>WM_MEASUREITEM</code> is not sent, instead item geometry data is used.</td>		</tr>		<tr>			<td>Status bar (<code>"msctls_statusbar32"</code>)</td>			<td>Flag <code>SBT_OWNERDRAW</code> (see message <code>SB_SETTEXT</code>)</td>			<td>Sends <code>WM_DRAWITEM</code> on per-part basis. Note <code>WM_MEASUREITEM</code> is not sent, instead part geometry data is used.</td>		</tr>		<tr>			<td>Menu item</td>			<td>Flag <code>MFT_OWNERDRAW</code> (see <code>InsertMenuItem()</code> or <code>SetMenuItemInfo()</code>)</td>			<td>Sends <code>WM_MEASUREITEM</code> as well as <code>WM_DRAWITEM</code> on per-item basis.</td>		</tr>	</tbody></table>

<p>This technique is quite simple for use as well as for implementation of owner drawing support in a new control: It is just about adding an <code>if</code> in <code>WM_PAINT</code> and <code>WM_PRINTCLIENT</code> handler and sending the mentioned messages to the parent window.</p>

<p>The most prominent limitation of the technique is quite obvious: You get all or nothing. Either the control (or the particular item) is painted completely by the control itself or - by applying the knob - the parent takes all the work on its own shoulder. There is no way how it can be used, for example, to just change a text color of some control item without reimplementation of all the painting code in parent window procedure.</p>

<h2>Custom Drawing</h2>

<p>Custom drawing is similar to owner drawing in that the control lets the parent to paint it or its part, but it gives the parent more liberty to cooperate with the control on the desired results. However more possibilities comes with a price: Custom drawing is more complex, both from the perspective of the control which supports it as well as from the perspective of an application which want to take advantage of it.</p>

<p>The basic idea is that the control sends the notification <code>NM_CUSTOMDRAW</code> multiple times, in various phases during painting of the control. Each time, the application has a possibility to augment the given painting phase to some degree, or (re)implement the phase on its own, and the application can also ask to get or not to get further more detailed notifications in subsequent drawing phases.</p>

<p>Parameter <code>LPARAM</code> of the notification is address of the structure <code>NMCUSTOMDRAW</code>, or (for some controls) some bigger structure having <code>NMCUSTOMDRAW</code> as its first member (in the same way as many notifications provide more data by sending a structure with <code>NMHDR</code> as its 1st member). Members of the structure are filled with default values/attributes the control wants to use during the given drawing phase. The application can override some of the attributes (e.g. font, some colors etc.) by resetting the appropriate structure member to another value, or it can even tell the control to skip the drawing phase altogether (so the application can paint something fairly different on its own).</p>

<p>The structure <code>NMCUSTOMDRAW</code> looks as follows:</p>

<pre lang="C"><span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> tagNMCUSTOMDRAWINFO {
    NMHDR     hdr;
    DWORD     dwDrawStage;
    HDC       hdc;
    RECT      rc;
    DWORD_PTR dwItemSpec;
    UINT      uItemState;
    LPARAM    lItemlParam;
} NMCUSTOMDRAW, *LPNMCUSTOMDRAW;</pre>

<p>The member <code>hdr</code> is the common notification header, so nothing interesting here.</p>

<p>The member <code>dwDrawStage</code> is crucial for custom draw processing. In each draw stage, the application can customize different things. We shall discuss this further soon.</p>

<p>The member <code>hdc</code> is the device context the control uses for the painting, so the application can partly customize it (e.g. by selecting another font to it), or use it for its own painting.</p>

<p>The member <code>rc</code> specifies the bounding rectangle for the painting, depending on the current stage, but note it is only defined for a stage <code>(CDDS_ITEM | CDDS_PREPAINT)</code> and (since <tt>COMCTL32.DLL</tt> version 6) for <code>CDDS_PREPAINT</code>.</p>

<p>The member <code>dwItemSpec</code> specifies what item is being painted. The interpretation of the value depends on the control. For example standard tree-view control stores <code>HTREEITEM</code> here, while list-view stores the index of the item here.</p>

<p>The member <code>uItemState</code> is a bit mask describing the state of the item to be painted, so if the application overrides the painting of an item, it knows whether the item is selected, focused, disabled etc., and can paint the item accordingly. Refer to MSDN for all the flags. They are not that important for understanding how the stuff works.</p>

<p>The member <code>lItemlParam</code> is (for item) the application-defined data associated with the item which actually any reasonable control should allow (and the standard control do).</p>

<p>Last but not least, the return value of the notification is also very important. The return value of the notification is actually a bit mask. Relevant bits the application can return depend on the current draw stage. In some stages, the app can also ask for more finer grained notifications after the stage is over and/or notifications on a nested level (e.g. for each item or subitem), by returning a proper return value from the parent window procedure.</p>

<p>The table below lists the draw stages of a complex control, which has some items and subitems of a kind. Simpler control without items or subitems would just use fewer draw stages.</p>


	<table class="grid"><thead>		<tr>			<th><code>dwDrawStage</code></th>			<th>Description</th>		</tr>	</thead>	<tbody>		<tr>			<td><code>CDDS_PREERASE</code></td>			<td>			<p>Sent before the control is being erased.</p>

			<p>The notification return value can use the following bits:</p>

			<ul>
				<li><code>CDRF_DODEFAULT</code> (0): Do the erasing normally.</li>				<li><code>CDRF_SKIPDEFAULT</code>: Skip the erasing (the app. should erase instead).</li>				<li><code>CDRF_NOTIFYPOSTERASE</code>: Asks control to also send <code>CDDS_POSTERASE</code> after the erasing..</li>			</ul>
			</td>		</tr>		<tr>			<td><code>CDDS_POSTERASE</code></td>			<td>			<p>Sent after the erasing, if the app. asked for it by returning <code>CDRF_NOTIFYPOSTERASE</code>.</p>

			<p>Return value is ignored.</p>
			</td>		</tr>		<tr>			<td><code>CDDS_PREPAINT</code></td>			<td>			<p>Sent before the control starts the painting.</p>

			<p>The notification return value can use the following bits:</p>

			<ul>
				<li><code>CDRF_DODEFAULT</code> (0): Do the painting (on control level) normally.</li>				<li><code>CDRF_SKIPDEFAULT</code>: Skip the whole painting, including painting of items and subitems (the app. should do it instead).</li>				<li><code>CDRF_DOERASE</code>: The control only paints the background. (Only on Vista and newer.)</li>				<li><code>CDRF_SKIPPOSTPAINT</code>: Skip painting of focus rectangle.</li>				<li><code>CDRF_NOTIFYITEMDRAW</code>: Asks control to also send the custom draw notification for each item.</li>				<li><code>CDRF_NOTIFYPOSTPAINT</code>: Asks control to also send <code>CDDS_POSTPAINT</code> after the control painting.</li>			</ul>
			</td>		</tr>		<tr>			<td><code>(CDDS_ITEM | CDDS_PREPAINT)</code></td>			<td>			<p>Sent before the control starts painting each item. Sent only if the <code>CDDS_PREPAINT</code> handler above used <code>CDRF_NOTIFYITEMDRAW</code>.</p>

			<p>The notification return value can use the following bits:</p>

			<ul>
				<li><code>CDRF_DODEFAULT</code> (0): Do the painting of the item normally.</li>				<li><code>CDRF_SKIPDEFAULT</code>: Skip the painting of the item, including painting of subitems (the app. should do it instead).</li>				<li><code>CDRF_NEWFONT</code>: The app. selected another font in the provided device context and the control should use it instead for painting the item.</li>				<li><code>CDRF_NOTIFYSUBITEMDRAW</code>: Asks control to also send the custom draw notification for each subitem.</li>				<li><code>CDRF_NOTIFYPOSTPAINT</code>: Asks control to also send <code>CDDS_POSTPAINT</code> after the item painting.</li>			</ul>
			</td>		</tr>		<tr>			<td><code>(CDDS_SUBITEM | CDDS_PREPAINT)</code></td>			<td>			<p>Sent before the control starts painting each subitem. Sent only if the <code>(CDDS_ITEM | CDDS_PREPAINT)</code> handler above used <code>CDRF_NOTIFYSUBITEMDRAW</code>.</p>

			<p>The notification return value can use the following bits:</p>

			<ul>
				<li><code>CDRF_DODEFAULT</code> (0): Do the painting of the subitem normally.</li>				<li><code>CDRF_SKIPDEFAULT</code>: Skip the painting of the subitem (the app. should do it instead).</li>				<li><code>CDRF_NEWFONT</code>: The app. selected another font in the provided device context and the control should use it instead for painting the subitem.</li>				<li><code>CDRF_NOTIFYPOSTPAINT</code>: Asks control to also send <code>CDDS_POSTPAINT</code> after the subitem painting.</li>			</ul>
			</td>		</tr>		<tr>			<td><code>(CDDS_SUBITEM | CDDS_POSTPAINT)</code></td>			<td>			<p>Sent after the subitem painting, if the app. asked for it by returning <code>CDRF_NOTIFYPOSTPAINT</code> from handling of the <code>(CDDS_SUBITEM | CDDS_PREPAINT)</code>.</p>

			<p>Return value is ignored.</p>
			</td>		</tr>		<tr>			<td><code>(CDDS_ITEM | CDDS_POSTPAINT)</code></td>			<td>			<p>Sent after the item painting, if the app. asked for it by returning <code>CDRF_NOTIFYPOSTPAINT</code> from handling of the <code>(CDDS_ITEM | CDDS_PREPAINT)</code>.</p>

			<p>Return value is ignored.</p>
			</td>		</tr>		<tr>			<td><code>CDDS_POSTPAINT</code></td>			<td>			<p>Sent after the control painting, if the app. asked for it by returning <code>CDRF_NOTIFYPOSTPAINT</code> from handling of the <code>CDDS_PREPAINT</code>.</p>

			<p>Return value is ignored.</p>
			</td>		</tr>	</tbody></table>

<p>Of course, you may also support the custom drawing in your custom controls, so apps can augment the control as they need. Such <code>WM_PAINT</code> handler may look like the following code skeleton presents. The code assumes the control uses items but not subitems. If your control needs also subitems, you have to simply add one more nested cycle with similar handling as the items get here:</p>

<pre lang="C"><span class="code-keyword">static</span> <span class="code-keyword">void</span>
CustomPaint(HWND hwnd, HDC hDC, RECT* rcDirty, BOOL bErase)
{
    NMCUSTOMDRAW nmcd;      <span class="code-comment">//</span><span class="code-comment"> The custom draw structure</span>
    LRESULT cdControlMode;  <span class="code-comment">//</span><span class="code-comment"> Return value of NM_CUSTOMDRAW for CDDS_PREPAINT</span>
    LRESULT cdItemMode;     <span class="code-comment">//</span><span class="code-comment"> Return value of NM_CUSTOMDRAW for CDDS_ITEM | CDDS_PREPAINT</span>

    <span class="code-comment">//</span><span class="code-comment"> Initialize members of the custom draw structure used for all the stages below:</span>
    nmcd.hdr.hwndFrom = hwnd;
    nmcd.hdr.idFrom = GetWindowLong(hwnd, GWL_ID);
    nmcd.hdr.code = NM_CUSTOMDRAW;
    nmcd.hdc = hDC;

    <span class="code-keyword">if</span>(bErase) {
        LRESULT cdEraseMode;

        <span class="code-comment">//</span><span class="code-comment"> Send control pre-erase notification:</span>
        nmcd.dwDrawStage = CDDS_PREERASE;
        cdEraseMode = SendMessage(GetParent(hwnd), WM_NOTIFY, nmcd.hdr.code, (LPARAM) &amp;nmcd);

        <span class="code-keyword">if</span>(!(cdEraseMode &amp; CDRF_SKIPDEFAULT)) {
            <span class="code-comment">//</span><span class="code-comment"> Do the erasing:</span>
            ...

            <span class="code-comment">//</span><span class="code-comment"> Send control post-erase notification:</span>
            <span class="code-keyword">if</span>(cdEraseMode &amp; CDRF_NOTIFYPOSTERASE) {
                nmcd.dwDrawStage = CDDS_POSTERASE;
                SendMessage(GetParent(hwnd), WM_NOTIFY, nmcd.hdr.code, (LPARAM) &amp;nmcd);
            }
        }
    }

    <span class="code-comment">//</span><span class="code-comment"> Send control pre-paint notification:</span>
    nmcd.dwDrawStage = CDDS_PREPAINT;
    GetClientRect(hwnd, &amp;nmcd.rc);
    cdControlMode = SendMessage(GetParent(hwnd), WM_NOTIFY, nmcd.hdr.code, (LPARAM) &amp;nmcd);

    <span class="code-keyword">if</span>(!(cdControlMode &amp; (CDRF_SKIPDEFAULT | CDRF_DOERASE))) {
        <span class="code-comment">//</span><span class="code-comment"> Do the control (as a whole) painting</span>
        <span class="code-comment">//</span><span class="code-comment"> (e.g. some kind of background or frame)</span>
        ...

        <span class="code-comment">//</span><span class="code-comment"> Iterate through all control items.</span>
        <span class="code-comment">//</span><span class="code-comment"> (If the control does not support any items, just omit all this for-loop.)</span>
        <span class="code-keyword">for</span>(...) {
            <span class="code-comment">//</span><span class="code-comment"> Send item pre-paint notification (if desired by the app):</span>
            <span class="code-keyword">if</span>(cdControlMode &amp; CDRF_NOTIFYITEMDRAW) {
                nmcd.dwDrawStage = CDDS_ITEM | CDDS_PREPAINT;
                <span class="code-comment">//</span><span class="code-comment"> Set some attributes describing the items. The app. can change</span>
                <span class="code-comment">//</span><span class="code-comment"> them to augment painting of the item:</span>
                nmcd.rc = ...;

                <span class="code-comment">//</span><span class="code-comment"> Identify the item (in per control specific way) so app. knows</span>
                <span class="code-comment">//</span><span class="code-comment"> what item is augmenting.</span>
                nmcd.dwItemSpec = ...;

                <span class="code-comment">//</span><span class="code-comment"> Tell app. if selection box, focus highlight etc. should be</span>
                <span class="code-comment">//</span><span class="code-comment"> painted for the item.</span>
                nmcd.uItemState = ...;

                <span class="code-comment">//</span><span class="code-comment"> Fill in also any data the app. may have associated with the</span>
                <span class="code-comment">//</span><span class="code-comment"> item so it can use them for augmenting of the control.</span>
                nmcd.lItemParam = ...;

                <span class="code-comment">//</span><span class="code-comment"> Send the notification.</span>
                cdItemMode = SendMessage(GetParent(hwnd), WM_NOTIFY, nmcd.hdr.code, (LPARAM) &amp;nmcd);
            } <span class="code-keyword">else</span> {
                cdItemMode = CDRF_DODEFAULT;
            }

            <span class="code-comment">//</span><span class="code-comment"> Do the item painting (unlesse suppressed by the app.)</span>
            <span class="code-keyword">if</span>(!(cdItemMode &amp; CDRF_SKIPDEFAULT)) {
                <span class="code-comment">//</span><span class="code-comment"> Note you should be ready for a case hdc may have different font selected</span>
                <span class="code-comment">//</span><span class="code-comment"> if (cdItemMode &amp; CDRF_NEWFONT)). In such case you should reset it to</span>
                <span class="code-comment">//</span><span class="code-comment"> the default control font after this particular item is painted:</span>
                ...

                <span class="code-comment">//</span><span class="code-comment"> Do the item (as a whole) painting</span>
                <span class="code-comment">//</span><span class="code-comment"> (e.g. some kind of item background or frame)</span>
                ...

                <span class="code-comment">//</span><span class="code-comment"> If the item is composed from a set of subitems, another similar</span>
                <span class="code-comment">//</span><span class="code-comment"> nested loop would be here to handle them. You would also need</span>
                <span class="code-comment">//</span><span class="code-comment"> yet another variable (cdSubitemMode) and handle the subitems</span>
                <span class="code-comment">//</span><span class="code-comment"> in similar way. nmcd.dwDrawStage would just set CDDS_SUBITEM</span>
                <span class="code-comment">//</span><span class="code-comment"> instead of CDDS_ITEM.</span>
                ...

                <span class="code-comment">//</span><span class="code-comment"> Do item "post-painting"</span>
                <span class="code-comment">//</span><span class="code-comment"> (e.g. paint a focus rectangle if the item is selected and</span>
                <span class="code-comment">//</span><span class="code-comment"> control has a focus).</span>
                ...

                <span class="code-comment">//</span><span class="code-comment"> Send item post-paint notification:</span>
                <span class="code-keyword">if</span>(cdItemMode &amp; CDRF_NOTIFYPOSTPAINT) {
                    nmcd.dwDrawStage = CDDS_ITEM | CDDS_POSTERASE;
                    SendMessage(GetParent(hwnd), WM_NOTIFY, nmcd.hdr.code, (LPARAM) &amp;nmcd);
                }
            }
        }

        <span class="code-comment">//</span><span class="code-comment"> Do control "post-painting":</span>
        <span class="code-keyword">if</span>(!(cdControlMode &amp; CDRF_SKIPPOSTPAINT)) {
            <span class="code-comment">//</span><span class="code-comment"> ...</span>
        }

        <span class="code-comment">//</span><span class="code-comment"> Send control post-paint notification:</span>
        <span class="code-keyword">if</span>(cdControlMode &amp; CDRF_NOTIFYPOSTPAINT) {
            nmcd.dwDrawStage = CDDS_POSTERASE;
            SendMessage(GetParent(hwnd), WM_NOTIFY, nmcd.hdr.code, (LPARAM) &amp;nmcd);
        }
    }
}

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_ERASEBKGND:
            <span class="code-keyword">return</span> FALSE;  <span class="code-comment">//</span><span class="code-comment"> Defer erasing into WM_PAINT</span>

        <span class="code-keyword">case</span> WM_PAINT:
        {
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &amp;ps);
            CustomPaint(hwnd, ps.hdc, &amp;ps.rcPaint, ps.fErase);
            EndPaint(hwnd, &amp;ps);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
        }

        <span class="code-keyword">case</span> WM_PRINTCLIENT:
        {
            RECT rc;
            GetClientRect(hwnd, &amp;rc);
            CustomPaint(hwnd, (HDC) wParam, &amp;rc, TRUE);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
        }

        <span class="code-comment">//</span><span class="code-comment"> ...</span>
    }
    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>(Note we handle control erasing directly in its painting handler. See one of the previous articles in this series, <a href="http://www.codeproject.com/Articles/617212/Custom-Controls-in-Win32-API-The-Painting">Custom Controls in Win32 API: The Painting</a>, for the discussion about this. The pre-erasing and post-erasing notifications might be of course sent from <code>WM_ERASEBKGND</code> if the control would do erasing there instead.)</p>

<p>The screenshot below shows the power of the custom drawing with the standard list view control. Complete MSVC project of the demo application this image is taken from can be downloaded at the top of this article.</p>

<p align="center"><img alt="Custom draw demo" height="350" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/customdraw.png" width="500"></p>

<div align="center" class="Caption">Custom draw demo screenshot</div>

<p>Ok, so that's about painting customization and now lets also take a look how to modify a behavior of a control.</p>

<h2>Decision-Making Notifications</h2>

<p>Many Windows standard controls send notifications which allow to modify some default logic of the control. In most cases, the notification defers some decision making how the control should behave in the current situation to the parent. Even with our definition of control customization, as involving non-trivial code on application side, it is a bit blurry whether this means using the control or customizing it. But lets talk at least a bit about it anyway.</p>

<p>An example of such notification in standard control is when user clicks to any (unselected) item in a tree view control. The control sends <code>TVN_SELCHANGING</code> to the parent window. When the parent returns zero from it, the control normally changes the selection (and then sends <code>TVN_SELCHANGED</code> notification). However when <code>TVN_SELCHANGING</code> returns non-zero, it instructs the control to suppress the change of selection.</p>

<p>This design pattern is used by many standard controls in many situations. When there is something what normally changes state of the control in a significant way, the control may want to allow some customization of that behavior and the control usually implements it in a way sketched by the following pseudo-code:</p>

<pre lang="C">...
<span class="code-keyword">if</span>(SendNotification(hwndParent, XXN_STATECHANGING, wParam, lParam) == <span class="code-digit">0</span>) {
    <span class="code-comment">//</span><span class="code-comment"> Do the control state change by modifying the control data</span>
    <span class="code-comment">//</span><span class="code-comment"> and (if needed) invalidate the control or its part to repaint</span>
    <span class="code-comment">//</span><span class="code-comment"> it so user can see the new control state.</span>
    ...

    <span class="code-comment">//</span><span class="code-comment"> Inform the parent the state has really changed.</span>
    SendNotification(hwndParent, XXN_STATECHANGED, wParam, lParam);
}
...
</pre>

<p>Whenever you implement a reusable custom control, you should consider, whether an application might want sometimes to disable the default behavior, or hook some other customized functionality to the events. If so, do not be lazy and add the notifications to support it.</p>

<p>There is one thing I would like to highlight: The implementation should always work so that return value of zero from the <code>XXN_STATECHANGING</code> triggers a behavior which is considered to be default by the control. This is important for two reasons:</p>

<ul>
	<li>When parent does not handle the notification, it should pass it into <code>DefWindowProc()</code>, and <code>DefWindowProc()</code> returns zero for <code>WM_NOTIFY</code>. Hence the control should behave in the default way in such case.</li>	<li>It is also important for forward compatibility: Often such notification is added into the control implementation only in some later version. The "default behavior" should in general correspond to older behavior so old applications not aware of the new notification continue to behave the same way, and new applications can change the behavior by handling the notification.</li></ul>

<h2>Superclassing and Subclassing</h2>

<p>Superclassing and subclassing are two techniques based on exchange of control window procedure. As such, these techniques have one very strong advantage: They both actually do not require any explicit support in the control being customized. However the power is not for free: You must be very careful to not break the logic of the original control procedure (especially if you don't have access to its source code).</p>

<h3>Superclassing</h3>

<p>Superclassing defines new window class, which is derived from an existing one. The following sample code provides a function for creating very simple superclassed control from a standard button.</p>

<pre lang="C"><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">tchar.h</span><span class="code-keyword">&gt;</span>
</span><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">windows.h</span><span class="code-keyword">&gt;</span>
</span>
<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> SuperButtonData_tag SuperButtonData;
<span class="code-keyword">struct</span> SuperButtonData_tag {
    <span class="code-comment">//</span><span class="code-comment"> ... data for the superclass implementation</span>
};


<span class="code-keyword">static</span> WNDPROC lpfnButtonProc;
<span class="code-keyword">static</span> <span class="code-keyword">int</span> cbButtonExtra;

<span class="code-keyword">static</span> LRESULT CALLBACK
SuperButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SuperButtonData* lpData = (SuperButtonData*) GetWindowLongPtr(hwnd, cbButtonExtra);

    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> Handle all messages we want to customize:</span>
        ...

        <span class="code-keyword">case</span> WM_NCCREATE:
            <span class="code-keyword">if</span>(!CallWindowProc(lpfnButtonProc, hwnd, uMsg, wParam, lParam))
                <span class="code-keyword">return</span> FALSE;
            lpData = (SuperButtonData*) malloc(<span class="code-keyword">sizeof</span>(SuperButtonData));
            <span class="code-keyword">if</span>(lpData == NULL)
                <span class="code-keyword">return</span> FALSE;
            ... <span class="code-comment">//</span><span class="code-comment"> Setup the lpData structure</span>
            SetWindowLongPtr(hwnd, cbButtonExtra, (LONG_PTR) lpData);
            <span class="code-keyword">return</span> TRUE;

        <span class="code-keyword">case</span> WM_NCDESTROY:
            <span class="code-keyword">if</span>(lpData)
                free(lpData);
            <span class="code-keyword">break</span>;
    }

    <span class="code-comment">//</span><span class="code-comment"> Instead of DefWindowProc(), we propagate messages into the original</span>
    <span class="code-comment">//</span><span class="code-comment"> button procedure for their default handling. Note it has to be called</span>
    <span class="code-comment">//</span><span class="code-comment"> indirectly via CallWindowProc().</span>
    <span class="code-keyword">return</span> CallWindowProc(lpfnButtonProc, hwnd, uMsg, wParam, lParam);
}

<span class="code-keyword">void</span>
RegisterSuperButton(<span class="code-keyword">void</span>)
{
    WNDSCLASS wc;

    GetClassInfo(NULL, _T(<span class="code-string">"</span><span class="code-string">BUTTON"</span>), &amp;wc);

    <span class="code-comment">//</span><span class="code-comment"> Remember some original data.</span>
    lpfnButtonProc = wc.lpfnWndProc;
    cbButtonExtra = wc.cbWndExtra;

    <span class="code-comment">//</span><span class="code-comment"> Name our class differently.</span>
    wc.lpszClassName = _T(<span class="code-string">"</span><span class="code-string">SUPERBUTTON"</span>);

    <span class="code-comment">//</span><span class="code-comment"> We register the class as local one for the .EXE module calling this function.</span>
    wc.style &amp;= ~CS_GLOBALCLASS;
    wc.hInstance = GetModuleHandle(NULL);

    <span class="code-comment">//</span><span class="code-comment"> Add few more extra bytes for our own purposes.</span>
    wc.cbWndExtra += <span class="code-keyword">sizeof</span>(SuperButtonData*);

    <span class="code-comment">//</span><span class="code-comment"> Set our own window procedure.</span>
    wc.lpfnWndProc = SuperButtonProc;

    <span class="code-comment">//</span><span class="code-comment"> Finally, register the new class.</span>
    RegisterClass(&amp;wc);
}</pre>

<p>As you can see, instead of initializing new <code>WNDCLASS</code>, we start with an existing window class, provide new window class name and augmenting some existing window class attributes. In particular we make the new window class use our window procedure (which can call the original one as the sample code demonstrates) and we also increase <code>wc.cbWndExtra</code> so our own data can be stored there. Plase pay special attention to the handling of <code>wc.cbWndExtra</code>. The original window class likely stores some data in the extra bytes, so we must be careful to not rewrite them. We store the original <code>wc.cbWndExtra</code> value and use it as an offset, where our own data are stored.</p>

<h3>Subclassing</h3>

<p>Subclassing works differently: It changes the window procedure of an existing control. This is fundamentally different approach: Superclassing defines new recipe (i.e. window class) for creating an arbitrary count of (customized) controls with <code>CreateWindow()</code> while subclassing changes single existing control instance referred with a given <code>HWND</code> handle.</p>

<p>Although this approach seems dirtier then the superclassing, sometimes it is very useful: you can modify look or behavior of a control you did not create (e.g. customizing control in a common control dialog, or a dialog created by a 3rd party DLL your application uses).</p>

<p>There are two ways how to implement it:</p>

<ul>
	<li>Using the specialized API for this purpose, i.e. the functions <code>SetWindowSubclass()</code> and its relatives.</li>	<li>The old legacy way is to manually reset pointer to window procedure with <code>SetWindowLongPtr(GWLP_WNDPROC)</code>.</li></ul>

<p>Lets start with the legacy way:</p>

<pre lang="C"><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">tchar.h</span><span class="code-keyword">&gt;</span>
</span><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">windows.h</span><span class="code-keyword">&gt;</span>
</span>
<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> SubButtonData_tag SubButtonData;
<span class="code-keyword">struct</span> SubButtonData_tag {
    WNDPROC lpfnButtonProc;
    <span class="code-comment">//</span><span class="code-comment"> ... data for the subclass implementation</span>
};

<span class="code-keyword">static</span> LPCTSTR pstrSubButtonId = _T(<span class="code-string">"</span><span class="code-string">SUBBUTON"</span>);


<span class="code-keyword">static</span> LRESULT CALLBACK
SubButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SubButtonData* lpData = (SubButtonData*) GetProp(hwnd, pstrSubButtonId);

    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> Handle all messages we want to customize:</span>
        ...
    }

    <span class="code-comment">//</span><span class="code-comment"> Instead of DefWindowProc(), we propagate messages into the original</span>
    <span class="code-comment">//</span><span class="code-comment"> button procedure for their default handling. Note it is called</span>
    <span class="code-comment">//</span><span class="code-comment"> indirectly via CallWindowProc().</span>
    <span class="code-keyword">return</span> CallWindowProc(lpData-&gt;lpfnButtonProc, hwnd, uMsg, wParam, lParam);
}

<span class="code-keyword">void</span>
SubclassButton(HWND hwnd)
{
    SubButtonData* lpData;

    lpData = (SubButtonData*) malloc(<span class="code-keyword">sizeof</span>(SubButtonData));
    lpData-&gt;lpfnButtonProc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);

    <span class="code-comment">//</span><span class="code-comment"> Setup subclass data as needed.</span>
    ...

    SetProp(hwnd, pstrSubButtonId, lpData);
    SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) SubButtonProc);
}

<span class="code-keyword">void</span>
UnsubclassButton(HWND hwnd)
{
    SubButtonData* lpData = (SubButtonData*) GetProp(hwnd, pstrSubButtonId);
    SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) lpData-&gt;lpfnButtonProc);
    RemoveProp(hwnd, pstrSubButtonId);
    free(lpData);
}</pre>

<p>The code is simple enough to understand without any discussion. But if you take a closer look on the code above, few issues can be observed:</p>

<ul>
	<li>If a single control is subclassed multiple times, <code>GetWindowLongPtr(GWLP_WNDPROC)</code> as called from the 2nd subclass gets pointer to window procedure of the 1st subclass. If 1st subclass decides to uninstall itself, 2nd subclass is not aware of it and still propagates messages to the window procedure it remembers: i.e. the procedure of 1st subclass. That will likely lead to a crash as 1st subclassed has uninstalled and likely released all resources required for its functioning.</li>	<li>There is no place where to store subclass specific data and hence the code uses <code>SetProp()</code> and <code>GetProp()</code>. These are much less effective then (e.g.) the extra bytes (as specified by window class). The window property functions are designed to store arbitrary count of data slots with the window so they are quite complex under the hood.</li></ul>

<p>The <code>SetWindowSubclass()</code> based API solves both of these issues (assuming all subclasses of the single control instance use this API) and therefore it should be preferred. However it is only available since <tt>COMCTL32.DLL</tt> version 6 or newer (i.e. on Windows XP, and only for application specifying its compatibility with version 6 of the library as discussed earlier in <a href="http://www.codeproject.com/Articles/620045/Custom-Controls-in-Win32-API-Visual-Styles">Custom Controls in Win32 API: Visual Styles</a>.)</p>

<p>Using the API, the code example above can be rewritten as follows:</p>

<pre lang="C"><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">tchar.h</span><span class="code-keyword">&gt;</span>
</span><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">windows.h</span><span class="code-keyword">&gt;</span>
</span><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">commctrl.h</span><span class="code-keyword">&gt;</span>
</span>
<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> SubButtonData_tag SubButtonData;
<span class="code-keyword">struct</span> SubButtonData_tag {
    <span class="code-comment">//</span><span class="code-comment"> ... data for the subclass implementation</span>
};

<span class="code-comment">//</span><span class="code-comment"> The API treats the pair (uSubclassId, SubButtonProc) as unique identification</span>
<span class="code-comment">//</span><span class="code-comment"> of the subclass. Assuming we do not need multiple subclass levels of</span>
<span class="code-comment">//</span><span class="code-comment"> the same control (which would share the subclass procedure), we do not need</span>
<span class="code-comment">//</span><span class="code-comment"> to deal much with the ID. Only if we would need such esoteric generality, we</span>
<span class="code-comment">//</span><span class="code-comment"> would use it for distinguishing among the subclasses.</span>
<span class="code-keyword">static</span> UINT_PTR uSubButtonId = <span class="code-digit">0</span>;


<span class="code-keyword">static</span> LRESULT CALLBACK
SubButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uSubclassId, DWORD_PTR dwData)
{
    SubButtonData* lpData = (SubButtonData*) dwData;

    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> Handle all messages we want to customize:</span>
        ...
    }

    <span class="code-keyword">return</span> DefSubclassProc(hwnd, uMsg, wParam, lParam);
}

<span class="code-keyword">void</span>
SubclassButton(HWND hwnd)
{
    SubButtonData* lpData;

    lpData = (SubButtonData*) malloc(<span class="code-keyword">sizeof</span>(SubButtonData));

    <span class="code-comment">//</span><span class="code-comment"> Setup subclass data as needed.</span>
    ...

    SetWindowSubclass(hwnd, SubButtonProc, uSubButtonId, (DWORD_PTR) lpData);
}

<span class="code-keyword">void</span>
UnsubclassButton(HWND hwnd)
{
    SubButtonData* lpData;

    GetWindowSubclass(hwnd, SubButtonProc, uSubButtonId, (DWORD_PTR*) &amp;lpData);
    RemoveWindowSubclass(hwnd, SubButtonProc, uSubButtonId);
    free(lpData);
}</pre>

<h3>Difficulties</h3>

<p>As I already noted in the introduction of this section, superclassing and subclassing require a big amount of care: Consider that whenever a control is implemented, its procedure handles a number of messages and usually many messages are supposed to play some part in a concert. For example, if the control responds to some mouse clicks, it likely handles button-down events as well as button-up events. If the new window procedures propagates one to the original procedure, but not the other, the internal state of the underlying control can easily end in an inconsistent state. Such concert of multiple message handlers in non-trivial controls can be played by dozen of messages and it is easy to introduce subtle bugs by overriding such messages.</p>

<p>This is especially complicated if you attempt to customize a control which evolves in a time. For example, if you customize a standard control in a dialog, you need to take into account that there are different versions of <tt>USER32.DLL</tt> and <tt>COMCTL32.DLL</tt> in various Windows versions, and that the control implementation evolves in them. Newer versions may have more features, new bugs, provide fixes of old bugs, and other subtle changes in their behavior and implementation.</p>

<p>Another difficulty is about notifications. Often, the derived window procedure may need to know when and how the underlying control state changes. The underlying window procedure usually informs the world about such change by sending a notification message to its parent. And that's the problem: The code of superclass/subclass window procedure cannot get the notification and hence you cannot easily react to the change of the control state, nor customize the notification. This often means that your application needs to send the notification back to the control in some way so the customized window procedure can react to it accordingly. We shall take a look on this problem in next article of this series.</p>

<p>To conclude, programming is about trade-offs: The techniques described in this section are indeed very powerful, but use of the power requires a big deal of responsibility and care, and it has also its limitations. Before you start customizing of a control, think what the original control does, how it is (likely) implemented, and how it can clash with your window procedure. And last but not least, test your new control against all relevant versions of the underlying control.</p>

<h2>Real World Code</h2>

<p>In previous articles, I usually provided some links to a real world code for studying of the topic presented in the article. This article is no exception.</p>

<p>Owner drawing in some standard control (re)implementation of the <a href="http://www.winehq.com/">Wine</a> project:</p>

<ul>
	<li>Button control: <a href="https://github.com/mirrors/wine/blob/master/dlls/user32/button.c">https://github.com/mirrors/wine/blob/master/dlls/user32/button.c</a></li>	<li>Listbox control: <a href="https://github.com/mirrors/wine/blob/master/dlls/user32/listbox.c">https://github.com/mirrors/wine/blob/master/dlls/user32/listbox.c</a></li>	<li>and many other controls in <tt>USER32.DLL</tt>.</li></ul>

<p>Custom drawing in some standard control (re)implementation of the Wine project:</p>

<ul>
	<li>Header control: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/header.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/header.c</a></li>	<li>Listview control: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/listview.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/listview.c</a></li>	<li>Rebar control: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/rebar.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/rebar.c</a></li>	<li>Treeview control: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/treeview.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/treeview.c</a></li>	<li>and many other controls in <tt>COMCTL32.DLL</tt>.</li></ul>

<p>Custom drawing support in a non-standard control implementation in <a href="http://mctrl.org/">mCtrl</a>:</p>

<ul>
	<li>Tree-list view control: <a href="https://github.com/mity/mctrl/blob/master/src/treelist.c">https://github.com/mity/mctrl/blob/master/src/treelist.c</a></li></ul>

<p>Superclassing used in Wine's (re)implementation of <tt>COMCTL32.DLL</tt> to provide support for visual themes for the base controls living in <tt>USER32.DLL</tt>:</p>

<ul>
	<li>Themed button: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/theme_button.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/theme_button.c</a></li>	<li>Themed combo: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32">https://github.com/mirrors/wine/blob/master/dlls/comctl32/theme_combo.c</a></li>	<li>Themed edit: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/theme_edit.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/theme_edit.c</a></li>	<li>Themed listbox: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/theme_listbox.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/theme_listbox.c</a></li></ul>

<p>Superclassing in mCtrl to backport some features of standard buttons to older Windows versions (themed <code>BS_ICON</code> on Windows XP, and <code>BS_SPLITBUTTON</code> on Windows 2000 and XP):</p>

<ul>
	<li>Button subclass: <a href="https://github.com/mity/mctrl/blob/master/src/button.c">https://github.com/mity/mctrl/blob/master/src/button.c</a></li></ul>

<p>Subclassing in Wine, for customizing the standard edit control for label editing in some more complex controls (e.g. list view) or for 4 IP components in IP address control:</p>

<ul>
	<li>List view control: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/listview.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/listview.c</a></li>	<li>IP address control: <a href="https://github.com/mirrors/wine/blob/master/dlls/comctl32/ipaddress.c">https://github.com/mirrors/wine/blob/master/dlls/comctl32/ipaddress.c</a></li></ul>

<h2>Next Time: Customized Control Encapsulation</h2>

<p>Today we took a look at several ways how to customize existing control rather then implementing a new one from scratch. We saw that it usually results in moving some code into the parent window's procedure.</p>

<p>That can be problematic for easy reuse of such controls in other dialogs, or even in context of other applications. The problem is even bigger if we are not in control of the parent window's code.</p>

<p>Therefore the next article will continue where this one stops and it will be dedicated to this problem, and describe few possibilities how to address it in your code.</p>


						</div>
						

						<div class="float-right" style="margin:20px 0 0 10px;border:1px solid #ccc">
						
						</div>
                        
                        
						
						<h2>License</h2>
						<div id="LicenseTerms"><p>This article, along with any associated source code and files, is licensed under <a href="http://www.codeproject.com/info/cpol10.aspx" rel="license">The Code Project Open License (CPOL)</a></p></div><h2 id="ctl00_AboutHeading">About the Author</h2>
						    

<div class="author-wrapper">

    <div class="pic-wrapper"> 
        <img id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberPhoto" class="profile-pic" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" style="border-width:0px;transform:rotate(1deg);">
    </div>

    <div class="container-member">  
        <b><a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberProfileLink" class="author" href="https://www.codeproject.com/Members/Martin-Mitas">Martin Mitáš</a></b>

        <table>
        <tbody><tr>
            <td rowspan="2" nowrap="" valign="middle">
            <div id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowOn" class="follow">
	            
	            
	            <a href="https://www.linkedin.com/profile/view?id=88607525"><img style="vertical-align:middle;border:0;height:24px;width:24px" alt="LinkedIn" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/linkedin-32.png"></a> 
            </div>
            </td>
            <td nowrap="nowrap">
                <div class="company">
                    <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberJobTitle">Team Leader</span>
	                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberCompany"></span>
                </div>
            </td>
            <td rowspan="2" style="padding-left:15px">
                <a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn" title="Have events related to this Member appear in your timeline" class="button unfollowed align-center invisible" data-enabletooltip="true" data-tooltip="Have the articles and posts from this member appear in your Timeline so you can stay up to date." style="display:none;">Follow<div class="tiny-text" style="margin-top:-3px;">this Member</div></a>
	<a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn" title="Unfollow this Member" class="button followed align-center invisible" data-enabletooltip="true" data-tooltip="Stop following this Member" style="display:none;">Unfollow</a>

            </td>
        </tr>
        <tr>
            <td>
                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberLocation">Czech Republic <img src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/CZ.gif" alt="Czech Republic" width="16px" height="11px"></span>
            </td>
        </tr>
        </tbody></table>
    </div>

    <div class="description">
        No Biography provided

        
    </div>

</div><br>
						
						

						<div class="clearfix"></div>

						<div style="padding-top:8px">
							
						</div>

					

				    
					</form>

				</div>

				
				<div class="bottom-promo"> 
				    
				</div>
				

                

				
				

					<h2>Comments and Discussions</h2>
					
					<p><img alt="Comment" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/NewComment.gif" width="12px" height="16px">
					<b>16 messages</b> have been posted for this article 
					Visit <b><a id="ctl00_ArticleLink" href="https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization">https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization</a></b> to post and view comments on 
					this article, or click <b><a id="ctl00_PrintWithMessage" href="https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization?display=PrintAll">here</a></b> 
					to get a print view with messages.</p>
					
				

			</div>
			
		</td>
		<td width="170px" class="article-wing-right">
			
		</td>
		</tr></tbody></table>

		
		<div class="theme1-background" style="height:2px" id="stickyStop"></div>

		<div class="extended tiny-text">
			<div class="row">
				<div class="float-left">
					<a id="ctl00_PermaLink" href="https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization">Permalink</a> | 
					<a id="ctl00_AdvertiseLink" href="http://developermedia.com/">Advertise </a> |
					<a id="ctl00_PrivacyLink" href="https://www.codeproject.com/info/privacy.aspx">Privacy</a> |
    				<a id="ctl00_CookiePolicyLink" href="https://www.codeproject.com/info/cookies.aspx">Cookies</a> |
                    <a id="ctl00_TermsOfUseLink" href="https://www.codeproject.com/info/TermsOfUse.aspx">Terms of Use</a> |
					<a id="ctl00_Mobile">Mobile</a>
					<br>
								
					
					Web06 |
					2.8.181119.1 |
					Last Updated 11 Dec 2014								
				</div>

                      

				<div class="float-right align-right">
					Article Copyright 2014 by Martin Mitáš<br>Everything else
					Copyright © <a href="mailto:webmaster@codeproject.com">CodeProject</a>, 1999-2018 <br>
				</div>

				

			</div>
		</div>
		

		<br clear="all">
		
			

	</div> 
	</div>
</div>






<script type="text/javascript" src="./Custom Controls in Win32 API_ Control Customization - CodeProject_files/MemberProfilePopup.min.js.下载"></script>
<script type="text/javascript">//<![CDATA[
$(document).ready(function () {
   processCodeBlocks.Initialise('#contentdiv');
   thumbnailer.Initialise('#contentdiv',700,600);
});
cookieconsent.initialise({
                                enabled : true,
                                cookie  : { domain: 'codeproject.com' },
                                palette : {
                                    popup: { background: '#ff9900' },
                                    button: { background: '#f5d948' }
                                },
                                law :  {
                                    showForAllRegions : true, 
                                    countryCode : 'CN' 
                                },
                                theme: 'edgeless',
                                type : 'opt-in',
                                content: {
                                    message: 'Like every other website we use cookies. By using our site you acknowledge that you have read and understand our <a href=\'/info/cookie.aspx\'>Cookie Policy</a>, <a href=\'/info/privacy.aspx\'>Privacy Policy</a>, and our <a href=\'/info/TermsOfUse.aspx\'>Terms of Service</a>.',
                                    href:    'https://www.codeproject.com/info/privacy.aspx'
                                },
                                revokable:true,
                                onStatusChange: function(status) {
                                    $.ajax({
                                		dataType  : 'json',
                                        data: JSON.stringify({ allowCookies : this.hasConsented() }),
                                        url: '/script/Common/webservices/CommonServices.aspx/SetCookieConsent',
                                        cache: false,
                                        type: 'POST',
                                        contentType: 'application/json'
                                    })
                                    console.log(this.hasConsented() ? 'enable cookies' : 'disable cookies');
                                    console.log(this.hasAnswered() ? 'has answered' : 'did not answer');
                                },
                            });
$(document).ready(function() { anchorAnimate();
});
$(document).ready(function(){
    $('#__EVENTVALIDATION').attr('autocomplete', 'off');
});
$(function() {
                        var followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember = new FollowService('/script/follow/webservices/followServices.aspx/', true);
                        followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember.initFollowObjectButtons({
                            item : { 
                                objectTypeId   : 1,
                                objectId       : 5807385
                            },
                            followButtonId   : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn',
                            unfollowButtonId : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn'
                        }, false);
                    });

//]]>
</script>





<div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div></body></html>